<?php
/**
 *  💡 免责声明：本软件不得用于商业用途，仅做学习交流
 *  ⚠️ 权利声明：本软件由版权人提供产品技术支持
 *  📅 项目编号：NX2025-0135
 */
namespace App\Jobs;

use App\Models\OrderBatch;
use App\Models\PointSetting;
use App\Models\Refund;
use App\Models\User;
use App\Service\AdvanceCard\AdvanceCardService;
use App\Service\Notifications\NotificationService;
use App\Service\Setting\BeanSettingService;
use App\Service\Setting\GroupSettingService;
use App\Service\User\PointAccountServices;
use App\Service\User\RewardAccountService;
use App\Service\User\WalletAccountService;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable;

class RefundJob implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    public $tries = 5;

    public $maxExceptions = 3;

    public $backoff = [30, 60, 300, 600, 1800];

    public $timeout = 300;

    public $refund;

    /**
     * 解除任务唯一锁的秒数.
     *
     * @var int
     */
    public $uniqueFor = 8000;

    public function __construct(
        Refund $refund
    ) {
        $this->refund = $refund->withoutRelations();
    }

    /**
     * 任务的 unique ID (唯一ID).
     *
     * @return string
     */
    public function uniqueId()
    {
        return $this->refund->id;
    }

    public function handle()
    {
        DB::transaction(function () {
            $this->validateRefund();  //验证
            $this->processPayment();  //退钱
            $this->processBean(); //退KC通证
            $this->rewardPoints(); // 奖积分到奖励余额.
            $this->updateOrderStatus(); //更新订单状态
            $this->recordCompletion(); //记录完成
            $this->sendNotifications(); //发送通知
            $this->addAdvanceCard();
        });
    }

    /**
     * 失败.
     */
    public function failed(Throwable $exception): void
    {
        $this->refund->update([
            'status' => 'failed',
            'failure_reason' => $exception->getMessage(),
        ]);

        $this->logOperation('job_failed', [
            'error' => $exception->getMessage(),
            'attempts' => $this->attempts(),
        ], 2);
    }

    /**
     * 验证退款.
     */
    private function validateRefund(): void
    {
        if ($this->refund->status !== 'approved') {
            throw new Exception('退款必须处于批准状态');
        }
        if ($this->refund->status == 'succeeded') {
            throw new Exception("退款 {$this->refund->id} 已处理");
        }
    }

    /**
     * 处理付款.
     */
    private function processPayment(): void
    {
        $refund = $this->refund;
        if ($refund->amount > 0) {
            WalletAccountService::make()->recharge(
                $refund->user_id,
                $refund->amount,
                "拼团失败系统自动退款 {$refund->amount}",
                true,
                3,
            );
        }
    }

    /**
     * 处理KC通证.
     */
    private function processBean(): void
    {
        $refund = $this->refund;
//        $total = $refund->gold_amount + $refund->burn;
//        $msg = "拼团失败系统退还KC通证，原:{$total}，实际:{$refund->gold_amount}，燃烧:{$refund->burn}";
        $beanPrice = BeanSettingService::make()->getSetting('PRICE');
        $amount = bcmul($refund->burn, $beanPrice, 2);
        $msg = sprintf('本场拼团失败%s次 KC通证转换到奖励余额:%s', $refund->number, $amount);
        BeanSettingService::make()->increaseTheAmountOfCombustion($refund->burn, $msg);
        RewardAccountService::make()->recharge($refund->user_id, $amount, 5, $msg);
        $order = OrderBatch::query()->find($refund->batches_id);
        $order->update([
            'bean_burning_reward' => $amount,
        ]);
//        BeanAccountService::make()->recharge(
//            $refund->user_id,
//            $refund->gold_amount,
//            $msg,
//            true,
//            3
//        );
    }

    /**
     * 奖积分到奖励余额.
     */
    private function rewardPoints()
    {
        $refund = $this->refund;
        $total = $refund->number;
        $setting = PointSetting::query()->first();  //combustion_integral
        $point = bcmul($total, $setting->group_reward_points, 2);
        $combustion_integral = bcmul($total, $setting->combustion_integral, 2);
        $amount = bcsub($point, $combustion_integral, 2);
        $pa = PointAccountServices::make()->consumption($refund->user_id, $point, '绿色积分燃烧' . $point);
        if ($pa) {
            $msg = sprintf('本场拼团失败%s次 绿色积分燃烧奖励:%s 实际到账:%s 手续费:%s ', $refund->number, $point, $amount, $combustion_integral);
            RewardAccountService::make()->recharge($refund->user_id, $amount, 5, $msg);
            GroupSettingService::make()->increaseTheAmountOfCombustion($combustion_integral, $msg);
            $order = OrderBatch::query()->find($refund->batches_id);
            $order->update([
                'point_burning_reward' => $amount,
            ]);
        } else {
            $user = User::query()->find($refund->user_id);
            NotificationService::make()->SystemNotify($user, '拼团失败%s单 绿色积分燃烧奖励 由于积分不足奖励发放失败');
        }
    }

    /**
     * 更新订单状态
     */
    private function updateOrderStatus(): void
    {
        $refund = $this->refund;
        $go = OrderBatch::query()->find($refund->batches_id);
        $go->update([
            'status' => 2,
        ]);
    }

    /**
     * 记录完成.
     */
    private function recordCompletion(): void
    {
        $this->refund->update([
            'status' => 'succeeded',
            'completed_at' => now(),
        ]);

        $this->logOperation('succeeded', [
            'refund_id' => $this->refund->getKey(),
        ]);
    }

    /**
     * 发送通知.
     */
    private function sendNotifications(): void
    {
//        Notification::send(
//            $this->refund->user,
//            new RefundProcessed($this->refund)
//        );
//
//        if ($this->refund->actual_amount < $this->refund->request_amount) {
//            Notification::send(
//                $this->refund->user,
//                new PartialRefundNotification($this->refund)
//            );
//        }
    }

    /**
     * 日志.
     * @param mixed $isFailed
     */
    private function logOperation(string $action, array $data = [], $isFailed = 1): void
    {
        if ($isFailed == 2) {
            Log::channel('group_refund_error')->info($action, $data);
        } else {
            Log::channel('group_refund_success')->info($action, $data);
        }
    }

    private function addAdvanceCard()
    {
        $refund = $this->refund;
        $order = OrderBatch::query()->find($refund->batches_id);
        if ($order->advance_card != 0) {
            $price = bcmul($refund->price, $order->order_count, 2);
            AdvanceCardService::make()
                ->voucherRecharge($order->user_id, $price, '拼团结束 退还代金券:' . $price);
        }
    }
}
